﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ZilLion.Service.Core.ConfigManager.Manager;
using ZilLion.Service.Core.DapperWrapper;
using ZilLion.Service.Core.Ioc;
using ZilLion.Service.Core.Log;
using ZilLion.Service.Core.Snowflake;
using ZilLion.Service.Core.WebSocket;
using ZilLion.Service.TaskPlatform.Controllers.Websocket;
using ZilLion.Service.TaskPlatform.Domain;
using ZilLion.Service.TaskPlatform.Domain.Entity;
using ZilLion.Service.TaskPlatform.Domain.ErrorReporter;
using ZilLion.Service.TaskPlatform.Domain.Respository.Interface;

namespace ZilLion.Service.TaskPlatform.Controllers.StateContainer
{
    public class NodeRunStateContainer
    {
        public NodeRunStateContainer(INodeRunMonitorRespository nodeRunMonitorRespository,
            INodeInfoRespository nodeInfoRespository)
        {
            #region 初始化缓存

            var nodes = nodeInfoRespository.GetNodeInfoEntities().ToList();
            var nodestates = nodeRunMonitorRespository.GetAllNodeMonitorInfo().ToList();
            foreach (var node in nodes)
            {
                var first = nodestates.FirstOrDefault(x => x.NodeId == node.Nodeid);
                if (first != null)
                    NodeRunStates.TryAdd(first.NodeId, first);
                else
                    NodeRunStates.TryAdd(node.Nodeid,
                        new NodeRunMonitorInfoEntity
                        {
                            NodeId = node.Nodeid,
                            NodeRunState = 0,
                            Nodename = node.Nodename,
                            Nodelastheartbeat = DateTime.Now
                        });
            }

            #endregion

            var refreshThread = new Thread(() =>
                {
                    while (true)
                    {
                        Thread.Sleep(1000 * 5 * 1); //1分钟检查


                        var states = new List<NodeRunMonitorInfoEntity>();
                        states.AddRange(NodeRunStates.Values);
                        try
                        {
                            foreach (var state in states)
                            {
                                #region 心跳超时报警

                                //当节点状态正常,但是已经有5分钟没有收到心跳,则视为心跳异常,需要报警
                                if (state.NodeRunState == 1 && state.Nodelastheartbeat.AddMinutes(5) < DateTime.Now)
                                {
                                    state.NodeRunState = 0; //节点状态为停止
                                    // 发送警告
                                    Task.Run(() =>
                                    {
                                        try
                                        {
                                            var reports = ZilLionConfigurationManager
                                                .GetConfigInstance<TaskManagerServiceConfig>().ErrorReports;
                                            QyWechatHelper.SendMessage(reports,
                                                $"节点{state.NodeId}已经超过5分钟未能发送心跳,已把节点状态置为已停止,请知晓");
                                        }
                                        catch (Exception e)
                                        {
                                            ZilLionLogManager.Instance().Error(e);
                                        }
                                    });
                                }

                                #endregion

                                var savedstate = nodeRunMonitorRespository.GetNodeMonitorInfoById(state.NodeId);
                                using (var unit = new UnitOfWork())
                                {
                                    if (savedstate != null)
                                        nodeRunMonitorRespository.MotifyPerformanceMonitorInfo(state, unit);
                                    else
                                        nodeRunMonitorRespository.AddPerformanceMonitorInfo(state, unit);
                                    unit.Complete();
                                }


                                #region 推送给oss

                                IocContainer.Resolve<TaskPlatformWebSocketHandler>()?.SendMessageToGroupAsync(
                                    JsonConvert.SerializeObject(new SocketKeyDto
                                    {
                                        ClientNo = "workmanager",
                                        ClientType = "taskoss"
                                    }),
                                    new SocketMessage
                                    {
                                        MessageId = SnowflakeIdCreater.Instance().GetNextId().ToString(),
                                        Data = JsonConvert.SerializeObject(state),
                                        MessageType = "updatenodestate"
                                    });

                                #endregion
                            }
                        }
                        catch (Exception e)
                        {
                            var json = JsonConvert.SerializeObject(states);
                            ZilLionLogManager.Instance().Error(e);
                            ZilLionLogManager.Instance().Info(json);
                        }
                    }
                })
                {IsBackground = true};
            refreshThread.SetApartmentState(ApartmentState.MTA);
            refreshThread.Start();
        }

        public ConcurrentDictionary<string, NodeRunMonitorInfoEntity> NodeRunStates { get; } =
            new ConcurrentDictionary<string, NodeRunMonitorInfoEntity>();
    }
}